﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace JudgeKernel.Judge
{
    internal class WIN32
    {
        #region WIN32函数的常量
        public const UInt32 CREATE_SUSPENDED = 0x00000004;
        public const UInt32 CREATE_NEW_CONSOLE = 0x00000010;
        public const UInt32 CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
        public const UInt32 DUPLICATE_SAME_ACCESS = 0x00000002;
        public const UInt32 WAIT_OBJECT_0 = 0x00000000;
        public const UInt32 WAIT_TIMEOUT = 0x00000102;
        public const UInt32 INFINITE = 0xFFFFFFFF;
        public const UInt32 STARTF_USESTDHANDLES = 0x00000100;

        const int JOB_OBJECT_TERMINATE_AT_END_OF_JOB = 0;
        const int JOB_OBJECT_POST_AT_END_OF_JOB = 1;

        //
        // Completion Port Messages for job objects
        //
        // These values are returned via the lpNumberOfBytesTransferred parameter
        //
        public const int JOB_OBJECT_MSG_END_OF_JOB_TIME = 1;
        public const int JOB_OBJECT_MSG_END_OF_PROCESS_TIME = 2;
        public const int JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT = 3;
        public const int JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO = 4;
        public const int JOB_OBJECT_MSG_NEW_PROCESS = 6;
        public const int JOB_OBJECT_MSG_EXIT_PROCESS = 7;
        public const int JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS = 8;
        public const int JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT = 9;
        public const int JOB_OBJECT_MSG_JOB_MEMORY_LIMIT = 10;

        //
        // Extended Limits
        //
        public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
        public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
        public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
        public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
        public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
        public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;

        public const int JOB_OBJECT_LIMIT_VALID_FLAGS = 0x0007ffff;

        public const int JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS = 0x000000ff;
        public const int JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS = 0x00003fff;
        public const int JOB_OBJECT_RESERVED_LIMIT_VALID_FLAGS = 0x0007ffff;
        #endregion

        #region WIN32函数

        [DllImport("Kernel32.dll", SetLastError = true)]
        static extern int CloseHandle(UIntPtr Handle);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
        public static extern bool CreateProcess(StringBuilder pApplicationName,
                                                String lpCommandLine,
                                                IntPtr lpProcessAttributes,
                                                IntPtr pThreadAttributes,
                                                bool bInheritHandles,
                                                UInt32 dwCreationFlags,
                                                StringBuilder lpEnvironment,
                                                StringBuilder lpCurrentDirectory,
                                                ref STARTUPINFOW lpStartupInfo,
                                                out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("Psapi.dll", SetLastError = true)]
        public static extern Boolean GetProcessMemoryInfo(IntPtr Process, out PROCESS_MEMORY_COUNTERS

ppsmemCounters, UInt32 cb);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern int GetProcessTimes(IntPtr hProcess,
                                                 out FILETIME lpCreationTime,
                                                 out FILETIME lpExitTime,
                                                 out FILETIME lpKernelTime,
                                                 out FILETIME lpUserTime);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern int FileTimeToSystemTime(ref FILETIME lpFileTime, out SYSTEMTIME

lpSystemTime);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, [MarshalAs

(UnmanagedType.LPTStr)] string pName);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr CreateIoCompletionPort(IntPtr FileHandle,
                                                              IntPtr ExistingCompletionPort,
                                                              UInt32 CompletionKey,
                                                              UInt32 NumberOfConcurrentThreads);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS

JobObjectInfoClass,
                                                         ref JOBOBJECT_EXTENDED_LIMIT_INFORMATION

lpJobObjectInfo,
                                                         UInt32 cbJobObjectInfoLength);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS

JobObjectInfoClass,
                                                         ref JOBOBJECT_ASSOCIATE_COMPLETION_PORT

lpJobObjectInfo,
                                                         UInt32 cbJobObjectInfoLength);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern int AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern UInt32 ResumeThread(IntPtr hThread);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern Boolean GetQueuedCompletionStatus(IntPtr CompletionPort, out UInt32

lpNumberOfBytes,
                                                               out UInt32 lpCompletionKey, IntPtr

lpOverlapped, UInt32 dwMilliseconds);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern Boolean CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe,
                                                ref SECURITY_ATTRIBUTES lpPipeAttributes, UInt32

nSize);
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern int DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle,
                                                 IntPtr hTargetProcessHandle,
                                                 out IntPtr lpTargetHandle,
                                                 UInt32 dwDesiredAccess,
                                                 bool bInheritHandle,
                                                 UInt32 dwOptions);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern int GetExitCodeProcess(IntPtr hProcess, out UInt32 lpExitCode);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer,
                                           uint nNumberOfBytesToRead,
                                           out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite,
                       out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool PeekNamedPipe(IntPtr hNamedPipe,
                           StringBuilder lpBuffer,
                           uint nBufferSize,
                           out uint lpBytesRead,
                           out uint lpTotalBytesAvail,
                           out uint lpBytesLeftThisMessage);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetCurrentProcess();

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool TerminateJobObject(IntPtr job, uint uExitCode);
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern uint GetLastError();

        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(uint dwDesiredAccess,
                                                bool bInheritHandle,
                                                uint dwProcessId);

        #endregion

        #region 函数的封送结构体

        [StructLayout(LayoutKind.Sequential)]
        public struct FILETIME
        {
            public UInt32 dwLowDateTime;
            public UInt32 dwHighDateTime;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEMTIME
        {
            public ushort wYear;
            public ushort wMonth;
            public ushort wDayOfWeek;
            public ushort wDay;
            public ushort wHour;
            public ushort wMinute;
            public ushort wSecond;
            public ushort wMilliseconds;
        }

        [StructLayoutAttribute(LayoutKind.Sequential)]
        public struct STARTUPINFOW
        {
            public UInt32 cb;
            public IntPtr lpReserved;
            public IntPtr lpDesktop;
            public String lpTitle;
            public UInt32 dwX;
            public UInt32 dwY;
            public UInt32 dwXSize;
            public UInt32 dwYSize;
            public UInt32 dwXCountChars;
            public UInt32 dwYCountChars;
            public UInt32 dwFillAttribute;
            public UInt32 dwFlags;
            public ushort wShowWindow;
            public ushort cbReserved2;
            public Byte lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public UInt32 dwProcessId;
            public UInt32 dwThreadId;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_MEMORY_COUNTERS
        {
            public UInt32 cb;
            public UInt32 PageFaultCount;
            public UInt32 PeakWorkingSetSize;
            public UInt32 WorkingSetSize;
            public UInt32 QuotaPeakPagedPoolUsage;
            public UInt32 QuotaPagedPoolUsage;
            public UInt32 QuotaPeakNonPagedPoolUsage;
            public UInt32 QuotaNonPagedPoolUsage;
            public UInt32 PagefileUsage;
            public UInt32 PeakPagefileUsage;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public UInt32 nLength;
            public IntPtr lpSecurityDescriptor;
            [MarshalAs(UnmanagedType.Bool)]
            public Boolean bInheritHandle;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
        {
            public LARGE_INTEGER PerProcessUserTimeLimit;
            public LARGE_INTEGER PerJobUserTimeLimit;
            public uint LimitFlags;
            public uint MinimumWorkingSetSize;
            public uint MaximumWorkingSetSize;
            public uint ActiveProcessLimit;
            public uint Affinity;
            public uint PriorityClass;
            public uint SchedulingClass;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
        {
            public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
            public IO_COUNTERS IoInfo;
            public uint ProcessMemoryLimit;
            public uint JobMemoryLimit;
            public uint PeakProcessMemoryUsed;
            public uint PeakJobMemoryUsed;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IO_COUNTERS
        {
            public ulong ReadOperationCount;
            public ulong WriteOperationCount;
            public ulong OtherOperationCount;
            public ulong ReadTransferCount;
            public ulong WriteTransferCount;
            public ulong OtherTransferCount;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT
        {
            public IntPtr CompletionKey;
            public IntPtr CompletionPort;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LARGE_INTEGER
        {
            long QuadPart;
        }
        #endregion
    }

    internal enum JOBOBJECTINFOCLASS
    {
        JobObjectBasicAccountingInformation = 1,
        JobObjectBasicLimitInformation,
        JobObjectBasicProcessIdList,
        JobObjectBasicUIRestrictions,
        JobObjectSecurityLimitInformation,
        JobObjectEndOfJobTimeInformation,
        JobObjectAssociateCompletionPortInformation,
        JobObjectBasicAndIoAccountingInformation,
        JobObjectExtendedLimitInformation,
        JobObjectJobSetInformation,
        MaxJobObjectInfoClass
    }

    internal enum JudeResult
    {
        OK = 2,
        RuntimeError = 9,
        TimeLimitExceeded = 5,
        MemoryLimitExceeded = 6,
        OutputLimitExceeded = 7,
        SystemError = 11
    }
}
